package com.ssl.rms.shiro.filters;


import com.ssl.rms.shiro.UsernamePasswordToken;
import com.ssl.rms.util.UserUtils;
import com.ssl.rms.utils.Constant;
import com.ssl.rms.utils.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Repository;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;


/**
 * 描述：重写表单验证的过滤器，可扩展验证码等
 *
 * @author ssl
 * @create 2018/02/07 15:17
 */
@Repository("formAuthenticationFilter")
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {

    /**
     * 自定义当前过滤器名称
     */
    public static final String LOGIN_FILTER_NAME = "formAuth";
    public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";
    public static final String DEFAULT_MESSAGE_PARAM = "message";


    /**
     * 验证码
     */
    private String captchaParam = DEFAULT_CAPTCHA_PARAM;
    /**
     * 返回的错误消息key
     */
    private String messageParam = DEFAULT_MESSAGE_PARAM;


    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse
            response) {
        /** 获取用户名 */
        String username = getUsername(request);
        /** 获取密码 */
        String password = getPassword(request);
        if (password == null) {
            password = "";
        }
        /** 获取记住我 */
        boolean rememberMe = isRememberMe(request);
        /** 获取客户端ip */
        String host = StringUtils.getRemoteAddr((HttpServletRequest) request);
        /** 获取验证码 */
        String captcha = getCaptcha(request);

        return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, this);
    }

    /**
     * 登录成功时候调用：可以将加载右侧菜单栏，放在这里
     *
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
                                     ServletResponse response) throws Exception {
        // 登录成功后，从session中加载菜单栏，session中没有，则到数据库中查找并放入session
        UserUtils.getMenus(Constant.MENU_TYPE_MENU);
        return super.onLoginSuccess(token, subject, request, response);
    }

    /**
     * 登录失败时候调用：将登录失败的原因返回
     *
     * @param token
     * @param e
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,
                                     ServletResponse response) {
        String className = e.getClass().getName(), message = "";
        if (IncorrectCredentialsException.class.getName().equals(className)
                || UnknownAccountException.class.getName().equals(className)) {
            message = "用户或密码错误, 请重试.";
        } else if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")) {
            message = StringUtils.replace(e.getMessage(), "msg:", "");
        } else {
            message = "系统异常，请联系管理员处理！";
            e.printStackTrace(); // 输出到控制台
        }
        request.setAttribute(getFailureKeyAttribute(), className);
        request.setAttribute(getMessageParam(), message);
        return true;
    }

    /**
     * 获取用户提交的验证码
     *
     * @param request
     * @return
     */
    protected String getCaptcha(ServletRequest request) {
        return WebUtils.getCleanParam(request, getCaptchaParam());
    }

    public String getCaptchaParam() {
        return captchaParam;
    }

    public String getMessageParam() {
        return messageParam;
    }

    public void setMessageParam(String messageParam) {
        this.messageParam = messageParam;
    }

    @Override
    protected String getName() {
        return LOGIN_FILTER_NAME;
    }
}
